extern crate regex;
extern crate chrono;

mod lexer;
mod cljcell;
mod util;
mod built_in_functions;

use crate::lexer::clj_code_to_chars::CljCharIterator;
use crate::lexer::clj_code_to_chars::CljLinesFromString;
use util::clj_util::NumberType;
use lexer::clj_lexer::CljLexer;
use lexer::my_clojure_reader::MyClojureReader;
use cljcell::clj_cell::CljCell;
use built_in_functions::my_clojure_interp::{CljFuncParam, CljFunc, MyClojureInterp};
use built_in_functions::clj_funs::{CljFunctions, MyCljFuncWraps};
use std::rc::Rc;
use chrono::NaiveDate;

fn to_cell() {
    let m = CljCharIterator::new(CljLinesFromString::new("(defn add [a b]
    (+ a b))"));
    let lex = CljLexer::new(m);
    let mut cljcell = MyClojureReader::new(lex);
    let rs = cljcell.get_expression();
    println!("{:?}", rs);
}

fn to_cell_1(code: &str) -> Rc<CljCell> {
    let m = CljCharIterator::new(CljLinesFromString::new(code));
    let lex = CljLexer::new(m);
    let mut cljcell = MyClojureReader::new(lex);
    let rs = cljcell.get_expression();
    //println!("{:?}", rs);
    return rs;
}

fn show_cell() {
    let mut lst:Vec<Rc<CljCell>> = Vec::new();
    lst.push(Rc::new(CljCell::Symbol (Rc::new(String::from("吴大富")))));
    lst.push(Rc::new(CljCell::Addition));
    lst.push(Rc::new(CljCell::LongClj (100)));
    let c = CljCell::CljList (lst);
    println!("{:?}", c);
}

fn add(a: i32, b: i32) -> i32 {
    a + b
}

#[test]
fn test_add_in_workspace() {
    //assert_eq!(add(100, 200), 300);
    to_cell_1("(loop [iter 1       acc  0]  (if (> iter 10)  (println acc)  (recur (+ 1 iter) (+ acc iter))))");
}

fn test_1() {
    let func_params: Vec<Rc<CljFuncParam>> = vec![Rc::new(CljFuncParam::new(String::from("吴大富"))), Rc::new(CljFuncParam::new(String::from("吴大贵"))), Rc::new(CljFuncParam::new(String::from("美羊羊")))];
    let m = CljFunc::new(func_params, Rc::new(CljCell::Null));
    let line: String = m.to_string();
    println!("{:?}", line);
}

fn test_2() {
    //let cell: Rc<CljCell> = to_cell_1("(defn my_add [x y] (+ y x))");
    //let cell: Rc<CljCell> = to_cell_1("(defn my_add ([x y z] (+ y x z)) ([x y] (+ y x)))");
    //let cell: Rc<CljCell> = to_cell_1("(defn add ([a c & b] (+ a c (apply * b))) ([a b] (+ a b)))");
    let cell: Rc<CljCell> = to_cell_1("(defn add ([a c & b] (+ a c (apply * b))) ([a [b & c]] (+ a b (apply * c))))");
    //println!("{:?}", cell);
    let inter = Box::new(MyClojureInterp::new());
    let ptr = Box::into_raw(inter);

    unsafe {
        let rs = (*ptr).my_eval(cell);
        println!("{:?}", (*(*ptr).ptr));
        let _ = Box::from_raw(ptr);
    }
}

// fn math<F>(func:F, a: i32, b: i32) where F: FnOnce(i32, i32)  -> i32 {
//     return func(a, b);
// }

fn test_3() {
    //let cell: Rc<CljCell> = to_cell_1("(defn my_add [x y] (+ y x))");
    let cell: Rc<CljCell> = to_cell_1("(defn my_add ([x y z] (+ y x z)) ([x y] (/ x y)))");
    //println!("{:?}", cell.clone());
    let inter: MyClojureInterp = MyClojureInterp::new();
    let fn_rs = inter.my_eval(cell);
    //println!("{:?}", fn_rs);

    let cell1: Rc<CljCell> = to_cell_1("(my_add 10 2.9)");
    let fn_rs1 = inter.my_eval(cell1);
    //println!("{:?}", inter.ptr);
    println!("{:?}", fn_rs1);
}

fn test_4() {
    //let cell: Rc<CljCell> = to_cell_1("(defn my_add [x y] (+ y x))");
    //let cell: Rc<CljCell> = to_cell_1("(= \"吴大富\" \"吴大富\")");
    let cell: Rc<CljCell> = to_cell_1("(<= 3 5.0)");
    println!("{:?}", cell.clone());
    let inter: MyClojureInterp = MyClojureInterp::new();
    let fn_rs = inter.my_eval(cell);
    println!("{:?}", fn_rs);

    //let cell1: Rc<CljCell> = to_cell_1("(my_add 10 2.9)");
    //let fn_rs1 = inter.my_eval(cell1);
    //println!("{:?}", fn_rs1);
}

fn add12(x: i32, y: i32) -> i32 {
    x + y
}

fn add21(x: i32, y: i32) -> i32 {
    x - y
}

//type GenericFnPtrMulti<A, B, C> = fn(A, B) -> C;
type GenericFnPtrMulti<T> = fn(T, T) -> T;

fn my_add<T: std::ops::Add<Output = T>> (a: T, b: T) -> T {
    a + b
}

fn test_date() {
    let date: NaiveDate = NaiveDate::parse_from_str("2023-01-01", "%Y-%m-%d").unwrap();
    println!("{:?}", date);
}

fn test_5() {
    let cell: Rc<CljCell> = to_cell_1("(let [a 1 b 2] (+ a b 1.01))");
    //println!("{:?}", cell.clone());
    let inter: MyClojureInterp = MyClojureInterp::new();
    let fn_rs = inter.my_eval(cell);
    println!("{:?}", fn_rs);
}

fn test_6() {
    let cell: Rc<CljCell> = to_cell_1("(loop [iter 1  acc  0] (if (> iter 1000) (println acc) (recur (+ 1 iter) (+ acc iter))))");
    println!("{:?}", cell.clone());
    let inter: MyClojureInterp = MyClojureInterp::new();
    inter.my_eval(cell);
}

fn test_7() {
    let cell: Rc<CljCell> = to_cell_1("(println \"吴大富是大帅哥！\")");
    println!("{:?}", cell.clone());
    let inter: MyClojureInterp = MyClojureInterp::new();
    inter.my_eval(cell);
}

fn test_8() {
    let cell: Rc<CljCell> = to_cell_1("(do (def n 100) (println n))");
    //println!("{:?}", cell.clone());
    let inter: MyClojureInterp = MyClojureInterp::new();
    inter.my_eval(cell);
}

fn test_9() {
    let mut lst: Vec<Rc<CljFuncParam>> = Vec::new();

    let mut r1 = CljFuncParam::new(String::from("A"));
    //r1.set_rest_param("rest_param_a".to_string());
    lst.push(Rc::new(r1));

    let mut r2 = CljFuncParam::new(String::from("B"));
    //r2.set_rest_param("rest_param_b".to_string());
    lst.push(Rc::new(r2));

    let mut r3 = CljFuncParam::new(String::from("C"));
    //r3.set_rest_param("rest_param_c".to_string());
    lst.push(Rc::new(r3));

    let c = CljFunctions::has_rest(&lst);
    println!("{:?}", c);
}

fn test_00() {
    let my_fun = MyCljFuncWraps::new();
    println!("{:?}", my_fun);
}

fn test_10() {
    let cell: Rc<CljCell> = to_cell_1("((fn [a b] (+ a b)) (+ 1 2 3) (* 1.2 3.5))");
    //let cell: Rc<CljCell> = to_cell_1("((fn [a b] (+ a b)) 3 2)");
    //println!("{:?}", cell.clone());
    let inter: MyClojureInterp = MyClojureInterp::new();
    let fn_rs = inter.my_eval(cell);
    println!("{:?}", fn_rs);
}

fn test_11() {
    let cell: Rc<CljCell> = to_cell_1("(#(+ %1 %2) 1.5 (+ (#(* %1 %2) 5 6) 5))");
    //let cell: Rc<CljCell> = to_cell_1("((fn [a b] (+ a b)) 3 2)");
    //println!("{:?}", cell.clone());
    let inter: MyClojureInterp = MyClojureInterp::new();
    let fn_rs = inter.my_eval(cell);
    println!("{:?}", fn_rs);
}

fn test_12() {
    let cell: Rc<CljCell> = to_cell_1("(>= 1 2 :else 3)");
    //let cell: Rc<CljCell> = to_cell_1("((fn [a b] (+ a b)) 3 2)");
    //println!("{:?}", cell.clone());
    let inter: MyClojureInterp = MyClojureInterp::new();
    let fn_rs = inter.my_eval(cell);
    println!("{:?}", fn_rs);
}

fn test_13() {
    let cell: Rc<CljCell> = to_cell_1("(defn my_add ([a b & c] (+ a b (apply + c))) ([a b] (+ a b)))");
    //println!("{:?}", cell.clone());
    let inter: MyClojureInterp = MyClojureInterp::new();
    let fn_rs = inter.my_eval(cell);
    //println!("{:?}", fn_rs);

    // unsafe {
    //     println!("*************");
    //     println!("{:?}", *inter.ptr);
    //     println!("$$$$$$$$$$$$$");
    // }

    let cell1: Rc<CljCell> = to_cell_1("(my_add 1 2 3 4 5 6)");
    let fn_rs1 = inter.my_eval(cell1);
    println!("{:?}", fn_rs1);
}

fn test_14() {
    let cell: Rc<CljCell> = to_cell_1("(defn my_add ([a c & b] (+ a c (apply * b))) ([a [b & c]] (+ a b (apply * c))))");
    //println!("{:?}", cell.clone());
    let inter: MyClojureInterp = MyClojureInterp::new();
    let fn_rs = inter.my_eval(cell);
    //println!("{:?}", fn_rs);

    let cell1: Rc<CljCell> = to_cell_1("(my_add 1 2 (+ 3 4))");
    let fn_rs1 = inter.my_eval(cell1);
    println!("{:?}", fn_rs1);
}

fn test_15() {
    let cell: Rc<CljCell> = to_cell_1("(cond (> 1 5) (println 1) :else (println \"吴大富\"))");
    //let cell: Rc<CljCell> = to_cell_1("(cond (> 1 5) (println 1) (> 11 5) (println \"吴大富\"))");
    println!("{:?}", cell.clone());
    let inter: MyClojureInterp = MyClojureInterp::new();
    let fn_rs = inter.my_eval(cell);
    println!("{:?}", fn_rs);
}

fn test_16() {
    //let cell: Rc<CljCell> = to_cell_1("(let [a 1 b 2] (+ a b))");
    let cell: Rc<CljCell> = to_cell_1("(cond (> 1 5) (println 1) (> 11 5) (println \"吴大富\"))");
    println!("{:?}", cell.clone());
    let inter: MyClojureInterp = MyClojureInterp::new();
    let fn_rs = inter.my_eval(cell);
    println!("{:?}", fn_rs);
}

fn test_17() {
    //let cell: Rc<CljCell> = to_cell_1("(let [a 1 b 2] (+ a b))");
    let cell: Rc<CljCell> = to_cell_1("(defn my [[f & r]] (if (not (nil? f)) (do (println f) (recur r))))");
    //println!("{:?}", cell.clone());
    let inter: MyClojureInterp = MyClojureInterp::new();
    let fn_rs = inter.my_eval(cell);
    //println!("{:?}", fn_rs);

    let cell1: Rc<CljCell> = to_cell_1("(my [1 2 3 4 5])");
    let fn_rs1 = inter.my_eval(cell1);
    println!("{:?}", fn_rs1);
}

fn test_18() {
    //let cell: Rc<CljCell> = to_cell_1("(let [a 1 b 2] (+ a b))");
    let cell: Rc<CljCell> = to_cell_1("(defn myadd [n] (if (= n 1) n (+ n (myadd (- n 1)))))");
    //println!("{:?}", cell.clone());
    let inter: MyClojureInterp = MyClojureInterp::new();
    let fn_rs = inter.my_eval(cell);
    //println!("{:?}", fn_rs);

    let cell1: Rc<CljCell> = to_cell_1("(myadd 100)");
    let fn_rs1 = inter.my_eval(cell1);
    println!("{:?}", fn_rs1);
}

fn test_19() {
    let cell: Rc<CljCell> = to_cell_1("(defn myadd ([n] (myadd n 0)) ([n num] (if (= n 0) num (recur (- n 1) (+ n num)))))");
    //println!("{:?}", cell.clone());
    let inter: MyClojureInterp = MyClojureInterp::new();
    let fn_rs = inter.my_eval(cell);
    //println!("{:?}", fn_rs);

    let cell1: Rc<CljCell> = to_cell_1("(myadd 3)");
    let fn_rs1 = inter.my_eval(cell1);
    println!("{:?}", fn_rs1);
}

fn test_20() {
    let cell: Rc<CljCell> = to_cell_1("(defmacro my-when [test & body] `(if ~test (list ~@body)))");
    println!("{:?}", cell.clone());
}

fn test_23() {
    //let cell: Rc<CljCell> = to_cell_1("(defn my_add [x y] (+ y x))");
    let cell: Rc<CljCell> = to_cell_1("(defn show_all [& all]
    (if (not (nil? (first all)))
        (do (println (first all))
            (recur (rest all)))))");
    //println!("{:?}", cell.clone());
    let inter: MyClojureInterp = MyClojureInterp::new();
    let fn_rs = inter.my_eval(cell);
    //println!("{:?}", fn_rs);

    let cell1: Rc<CljCell> = to_cell_1("(show_all 1 2 3)");
    let fn_rs1 = inter.my_eval(cell1);
    //println!("{:?}", inter.ptr);
    println!("{:?}", fn_rs1);
}

fn test_21() {
    //let cell: Rc<CljCell> = to_cell_1("(defmacro my-when1 [test & body] (list 'if test (cons 'do body)))");
    //println!("{:?}", cell.clone());
    //let m = CljCharIterator::new(CljLinesFromString::new("(list 'if test (cons 'do body))"));
    let m = CljCharIterator::new(CljLinesFromString::new("`(if ~test (list ~@body))"));
    let mut lex = CljLexer::new(m);
    lex.next();
    println!("{:?}", lex.current());

    lex.next();
    println!("{:?}", lex.current());

    lex.next();
    println!("{:?}", lex.current());

    lex.next();
    println!("{:?}", lex.current());

    lex.next();
    println!("{:?}", lex.current());

    lex.next();
    println!("{:?}", lex.current());

    lex.next();
    println!("{:?}", lex.current());

    lex.next();
    println!("{:?}", lex.current());

    lex.next();
    println!("{:?}", lex.current());

    lex.next();
    println!("{:?}", lex.current());

    lex.next();
    println!("{:?}", lex.current());
}

fn test_22() {
    let m = CljCharIterator::new(CljLinesFromString::new("(list 'if test (cons 'do body))"));
    //let m = CljCharIterator::new(CljLinesFromString::new("`(if ~test (list ~@body))"));
    let lex = CljLexer::new(m);
    let mut cljcell = MyClojureReader::new(lex);
    let rs = cljcell.get_expression();
    println!("{:?}", rs);
}

fn test_24() {
    let cell: Rc<CljCell> = to_cell_1("(rest [1 2 3])");
    //let cell: Rc<CljCell> = to_cell_1("((fn [a b] (+ a b)) 3 2)");
    println!("{:?}", cell.clone());
    let inter: MyClojureInterp = MyClojureInterp::new();
    let fn_rs = inter.my_eval(cell);
    println!("{:?}", fn_rs);
}

fn main() {

    //let closure = |a: i32, b: i32| -> i32 { a + b };
    //println!("{:?}", math(closure, 12, 21));

    //test_24();
    //test_23();
    //test_22();
    //test_21();
    test_20();
    //test_19();
    //test_18();
    //test_17();
    //test_16();
    //test_15();
    // test_14();
    // test_13();
    // test_12();
    // test_11();
    // test_10();
    // test_9();
    // test_8();
    // test_7();
    // test_6();
    // test_5();
    // test_4();
    // test_3();
    // test_date();
    // test_00();

    // 定义函数指针类型
    //let func_ptr: fn(i32, i32) -> i32 = add12;
    //let func_ptr: GenericFnPtrMulti<i32> = add12;
    // let func_ptr: GenericFnPtrMulti<i32> = add12;
    // println!("Result: {}", func_ptr(3, 5)); // 输出 8
    //
    // let func_ptr1: GenericFnPtrMulti<f64> = my_add;
    // println!("Result: {}", func_ptr1(3.3, 5.5)); // 输出 8
    //println!("Result: {}", my_add(1.2, 2.1));

    //lex_case();
    //test_1();
    // let m = CljFuncParam::new(String::from("吴大富"));
    // let line: String = m.to_string();
    // println!("{:?}", line);

    //to_cell_1("(defn add   ([a c & b] (+ a c (apply * b)))  ([a b] (+ a b)))");
    //to_cell_1("(loop [iter 1       acc  0]  (if (> iter 10)  (println acc)  (recur (+ 1 iter) (+ acc iter))))");
    //to_cell_1("(defn my_add ([x y z] (+ y x z)) ([x y] (+ y x)))");
    //to_cell_1("(#(println %) \"吴大富是一个大帅哥！\")");
    //to_cell_1("(#(+ %1 %2) 1 2)");
    //to_cell_1("((fn [a b] (+ a b)) (+ 1 2 3) 2)");
    //to_cell_1("(def n 0)");
    //to_cell_1("{:a 12 :b \"吴大富\"}");
    //to_cell_1("(do (def n 10) (println n))");
    //lex_case();
    //to_cell();

}
